#pragma once
//导出的多线程，让程序可以真多线程执行代码
#include "Event.h"
#include "ThreadNames.h"
#include "ThreadContext.h"
#include "Runtime/Platform/PlatformAPI.h"
namespace Alice {
	extern int32 GRenderThreadPollPeriodMs;
	struct RenderThreadStatics
	{
		static std::atomic<ENamedThreads> RenderThread;
		static std::atomic<ENamedThreads> RenderThread_Local;

		static ENamedThreads GetRenderThread()
		{
			return RenderThread.load();
		}
		static ENamedThreads GetRenderThread_Local()
		{
			return RenderThread_Local.load();
		}
		static void SetRenderThread(ENamedThreads Thread)
		{
			RenderThread=Thread;
		}
		static void SetRenderThread_Local(ENamedThreads Thread)
		{
			RenderThread_Local=Thread;
		}
	};
	FORCEINLINE ENamedThreads GetRenderThread()
	{
		return RenderThreadStatics::RenderThread.load(std::memory_order_relaxed);
	}

	FORCEINLINE ENamedThreads GetRenderThread_Local()
	{
		return RenderThreadStatics::RenderThread_Local.load(std::memory_order_relaxed);
	}

	FORCEINLINE void SetRenderThread(ENamedThreads Thread)
	{
		RenderThreadStatics::RenderThread.store(Thread,std::memory_order_relaxed);
	}

	FORCEINLINE void SetRenderThread_Local(ENamedThreads Thread)
	{
		RenderThreadStatics::RenderThread_Local.store(Thread,std::memory_order_relaxed);
	}
	FORCEINLINE ENamedThreads GetThreadIndex(ENamedThreads ThreadAndIndex)
	{
		return (((int32)ThreadAndIndex & (int32)ENamedThreads::ThreadIndexMask) == (int32)ENamedThreads::AnyThread) ? ENamedThreads::AnyThread : ENamedThreads((int32)ThreadAndIndex & (int32)ENamedThreads::ThreadIndexMask);
	}
	FORCEINLINE ENamedThreads ExtractThreadName(ENamedThreads ThreadAndIndex)
	{
		return (((int32)ThreadAndIndex & (int32)ENamedThreads::ThreadIndexMask) == (int32)ENamedThreads::AnyThread) ? ENamedThreads::AnyThread : ENamedThreads((int32)ThreadAndIndex & (int32)ENamedThreads::ThreadIndexMask);
	}
	FORCEINLINE int32 GetQueueIndex(ENamedThreads ThreadAndIndex)
	{
		return ((int32)ThreadAndIndex & (int32)ENamedThreads::QueueIndexMask) >> (int32)ENamedThreads::QueueIndexShift;
	}
	FORCEINLINE int32 GetTaskPriority(ENamedThreads ThreadAndIndex)
	{
		return ((int32)ThreadAndIndex & (int32)ENamedThreads::TaskPriorityMask) >> (int32)ENamedThreads::TaskPriorityShift;
	}
	FORCEINLINE int32 GetThreadPriorityIndex(ENamedThreads ThreadAndIndex)
	{
		int32 Result = ((int32)ThreadAndIndex & (int32)ENamedThreads::ThreadPriorityMask) >> (int32)ENamedThreads::ThreadPriorityShift;
		return Result;
	}
	FORCEINLINE ENamedThreads SetPriorities(ENamedThreads ThreadAndIndex, ENamedThreads ThreadPriority, ENamedThreads TaskPriority)
	{
		return ENamedThreads((int32)ThreadAndIndex | (int32)ThreadPriority | (int32)TaskPriority);
	}
	FORCEINLINE ENamedThreads SetPriorities(ENamedThreads ThreadAndIndex, int32 PriorityIndex, bool bHiPri)
	{
		return ENamedThreads((int32)ThreadAndIndex | (PriorityIndex << (int32)ENamedThreads::ThreadPriorityShift) | (bHiPri ? (int32)ENamedThreads::HighTaskPriority : (int32)ENamedThreads::NormalTaskPriority));
	}
	FORCEINLINE ENamedThreads SetThreadPriority(ENamedThreads ThreadAndIndex, ENamedThreads ThreadPriority)
	{
		return ENamedThreads((int32)ThreadAndIndex | (int32)ThreadPriority);
	}
	FORCEINLINE ENamedThreads SetTaskPriority(ENamedThreads ThreadAndIndex, ENamedThreads TaskPriority)
	{
		return ENamedThreads((int32)ThreadAndIndex | (int32)TaskPriority);
	}
	class Thread
	{
		static uint32 RunnableTlsSlot;
	public:
		static uint32 GameThreadID;
		static uint32 RenderThreadID;
		static uint32 AudioThreadID;
		static uint32 GetTlsSlot();
		static Thread* GetRunnableThread()
		{
			Thread* thread = (Thread*)PlatformTLS::GetTlsValue( RunnableTlsSlot );
			return thread;
		}
		static Thread* Create(const char * name,ThreadContext* threadContext);
		
		void Entry();
		virtual bool Kill( bool bShouldWait = true );
		virtual void WaitForCompletion();
		const std::thread::id GetThreadID() const
		{
			return mThreadID;
		}
		Thread(const char *name);
		virtual ~Thread();

	protected:
		virtual bool CreateInternal(ThreadContext* threadContext);
		void SetTls();
		void FreeTls();
		ThreadContext* mThreadContext;
		Event* mThreadInitSyncEvent;
		std::thread *mThread;
		std::thread::id mThreadID;
		char mThreadName[64];
	private:
		virtual void PostCreate() {};
	};
}